package org.dromara.bean.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.yungouos.pay.wxpay.WxPay;
import lombok.extern.slf4j.Slf4j;
import org.dromara.bean.constant.*;
import org.dromara.bean.controller.PaymentController;
import org.dromara.bean.domain.*;
import org.dromara.bean.domain.pay.OrderModel;
import org.dromara.bean.domain.vo.HisDoctorVo;
import org.dromara.bean.domain.vo.HisPatientVo;
import org.dromara.bean.domain.vo.Result;
import org.dromara.bean.mapper.*;
import org.dromara.bean.service.IBaseMemberRefundService;
import org.dromara.bean.service.IBasePaymentService;
import org.dromara.bean.util.BusinessCodeUtil;
import org.dromara.bean.util.wxApi.WXHandleUtil;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.domain.model.ReturnOrderModel;
import org.dromara.common.core.domain.model.WxRefundResponseDTO;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.dromara.bean.domain.bo.HisRegistrationBo;
import org.dromara.bean.domain.vo.HisRegistrationVo;
import org.dromara.bean.service.IHisRegistrationService;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 挂号记录Service业务层处理
 *
 * @author Lion Li
 * @date 2024-11-30
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class HisRegistrationServiceImpl implements IHisRegistrationService {

    private final HisRegistrationMapper baseMapper;
    private final HisDoctorMapper doctorMapper;

    private final HisPatientMapper patientMapper;

    private final SysDictDataMapper sysDictDataMapper;

    private final HisRegistrationMapper registrationMapper;

    private final HisMemberMapper memberMapper;
    private final HisDepMapper depMapper;
    private final SysOssMapper sysOssMapper;

    @Autowired
    PaymentController paymentController;

    private final BusinessCodeUtil businessCodeUtil;


    private final IBaseMemberRefundService memberRefundService;


    private final WXHandleUtil wxHandleUtil;


    /**
     * 查询挂号记录
     *
     * @param id 主键
     * @return 挂号记录
     */
    @Override
    public HisRegistrationVo queryById(Long id) {
        HisRegistrationVo registrationVo = baseMapper.selectVoById(id);
        if (registrationVo == null) {
            throw new RuntimeException("挂号记录不存在");
        }

        Long doctorId = registrationVo.getDoctorId();
        if (doctorId == null) {
            return registrationVo; // 无医生ID时直接返回
        }
        HisDoctorVo doctorVo = doctorMapper.selectDoctorById(doctorId);
        if (doctorVo == null) {
            throw new RuntimeException("关联的医生不存在，医生ID：" + doctorId);
        }

        String depIdStr = doctorVo.getDepId();
        if (StringUtils.isNotBlank(depIdStr)) {
            String[] depIdArray = depIdStr.split(",");
            Set<Integer> depIdSet = new HashSet<>();
            for (String depId : depIdArray) {
                try {
                    depIdSet.add(Integer.parseInt(depId.trim())); // 收集有效科室ID
                } catch (NumberFormatException e) {
                    log.warn("无效的科室ID格式：{}，医生ID：{}", depId, doctorId);
                }
            }

            Map<Integer, String> depTitleMap = new HashMap<>();
            if (!depIdSet.isEmpty()) {
                List<HisDep> deps = depMapper.selectList(
                    new LambdaQueryWrapper<HisDep>()
                        .in(HisDep::getId, depIdSet)
                        .select(HisDep::getId, HisDep::getTitle)
                );
                deps.forEach(dep -> depTitleMap.put(Math.toIntExact(dep.getId()), dep.getTitle()));
            }

            List<String> depTitles = new ArrayList<>();
            for (String depId : depIdArray) {
                try {
                    Integer idInt = Integer.parseInt(depId.trim());
                    depTitles.add(depTitleMap.getOrDefault(idInt, "未知科室"));
                } catch (NumberFormatException e) {
                    depTitles.add("无效科室ID");
                }
            }
            doctorVo.setTitle(String.join(",", depTitles));
        }
        registrationVo.setHisDoctorVo(doctorVo);
        return registrationVo;
    }

    /**
     * 分页查询挂号记录列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 挂号记录分页列表
     */
    @Override
    public TableDataInfo<HisRegistrationVo> queryPageList(HisRegistrationBo bo, PageQuery pageQuery) {
        Page<HisRegistrationVo> page = baseMapper.registrationList(pageQuery.build(), bo);
        List<HisRegistrationVo> records = page.getRecords();
        if (records.isEmpty()) {
            return TableDataInfo.build(page);
        }

        // 收集所有医生ID，批量查询医生信息
        Set<Long> doctorIdSet = records.stream()
            .map(HisRegistrationVo::getDoctorId)
            .filter(Objects::nonNull)
            .collect(Collectors.toSet());

        // 批量查询医生信息
        Map<Long, HisDoctor> doctorMap;
        if (!doctorIdSet.isEmpty()) {
            List<HisDoctor> doctorList = doctorMapper.selectBatchIds(doctorIdSet);
            doctorMap = doctorList.stream()
                .collect(Collectors.toMap(HisDoctor::getId, Function.identity()));
        } else {
            doctorMap = new HashMap<>();
        }

        // 收集所有科室ID  批量查询科室名称
        Set<Long> depIdSet = new HashSet<>();
        for (HisDoctor doctor : doctorMap.values()) {
            String depIdStr = doctor.getDepId();
            if (StringUtils.isNotBlank(depIdStr)) {
                String[] depIds = depIdStr.split(",");
                for (String depId : depIds) {
                    try {
                        depIdSet.add(Long.parseLong(depId.trim()));
                    } catch (NumberFormatException e) {
                        log.warn("无效的科室ID格式：{}", depId);
                    }
                }
            }
        }
        // 批量查询科室信息
        Map<Long, String> depTitleMap;
        if (!depIdSet.isEmpty()) {
            List<HisDep> depList = depMapper.selectList(
                new LambdaQueryWrapper<HisDep>()
                    .in(HisDep::getId, depIdSet)
                    .select(HisDep::getId, HisDep::getTitle)
            );
            depTitleMap = depList.stream()
                .collect(Collectors.toMap(HisDep::getId, HisDep::getTitle));
        } else {
            depTitleMap = new HashMap<>();
        }

        // 为每条挂号记录设置医生名称和科室信息
        records.forEach(item -> {
            Long doctorId = item.getDoctorId();
            HisDoctor doctorVo = doctorMap.get(doctorId);
            if (doctorVo != null) {
                // 设置医生名称
                item.setDoctorName(doctorVo.getName());
                // 处理科室信息
                String depIdStr = doctorVo.getDepId();
                if (StringUtils.isNotBlank(depIdStr)) {
                    String[] depIds = depIdStr.split(",");
                    List<String> depTitles = new ArrayList<>();
                    for (String depId : depIds) {
                        try {
                            Long depIdLong = Long.parseLong(depId.trim());
                            depTitles.add(depTitleMap.getOrDefault(depIdLong, "未知科室"));
                        } catch (NumberFormatException e) {
                            depTitles.add("无效科室ID");
                        }
                    }
                    item.setTitle(String.join(",", depTitles));
                } else {
                    item.setTitle(""); // 无科室ID时设为空
                }
            } else {
                // 医生不存在时的默认值
                item.setDoctorName("未知医生");
                item.setTitle("");
            }
        });

        return TableDataInfo.build(page);
    }

    /**
     * 查询符合条件的挂号记录列表
     *
     * @param bo 查询条件
     * @return 挂号记录列表
     */
    @Override
    public List<HisRegistrationVo> queryList(HisRegistrationBo bo) {
        LambdaQueryWrapper<HisRegistration> lqw = buildQueryWrapper(bo);
        return baseMapper.registrationList(bo);
    }

    private LambdaQueryWrapper<HisRegistration> buildQueryWrapper(HisRegistrationBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<HisRegistration> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getMemberId() != null, HisRegistration::getMemberId, bo.getMemberId());
        lqw.eq(bo.getPatientId() != null, HisRegistration::getPatientId, bo.getPatientId());
        lqw.eq(bo.getRegistrationTime() != null, HisRegistration::getRegistrationTime, bo.getRegistrationTime());
        lqw.eq(bo.getPayTime() != null, HisRegistration::getPayTime, bo.getPayTime());
        lqw.eq(bo.getStatus() != null, HisRegistration::getStatus, bo.getStatus());
        return lqw;
    }

    /**
     * 新增挂号记录
     *
     * @param bo 挂号记录
     * @return 是否新增成功
     */
    @Override
    public HisRegistration insertByBo(HisRegistrationBo bo) {
        // 获取当前登录的用户信息
        LoginUser loginUser = LoginHelper.getLoginUser();
        // 设置业务对象的会员ID为当前登录用户的用户ID
        bo.setMemberId(loginUser.getUserId());

        // 查询当前用户是否存在未完成挂号订单
        if (baseMapper.selectCount(new LambdaQueryWrapper<HisRegistration>()
            .eq(HisRegistration::getMemberId, loginUser.getUserId())
            .in(HisRegistration::getStatus, 100, 200)
            .eq(HisRegistration::getDelFlag, 0)
            .eq(HisRegistration::getPatientId, bo.getPatientId())
            .like(HisRegistration::getRegistrationTime, bo.getRegistrationTime())
            .eq(HisRegistration::getDoctorId, bo.getDoctorId())) > 0) {
            throw new RuntimeException("本医生"+ bo.getRegistrationTime() +"已有挂号订单");
        }
        String number = businessCodeUtil.genCode(BusinessCodeTypeConstant.HIS_REGISTRATION_EXAMINE);
        bo.setOrderNumber(number);
        // 获取医生信息,插入挂号费
        HisDoctorVo hisDoctorVo = doctorMapper.selectVoById(bo.getDoctorId());
        bo.setTotalPrice(hisDoctorVo.getPrice());
        //设置默认状态
        //如果医生无挂号费设置状态为已支付
        if (hisDoctorVo.getPrice().compareTo(BigDecimal.ZERO) <= 0) {
            bo.setStatus((long) OrderStatusConstant.REGISTER_PAID);
        } else {
            bo.setStatus((long) OrderStatusConstant.REGISTER_FOR_PAY);
        }
        HisRegistration add = MapstructUtils.convert(bo, HisRegistration.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return add;
    }

    /**
     * 修改挂号记录
     *
     * @param bo 挂号记录
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(HisRegistrationBo bo) {
        HisRegistration update = MapstructUtils.convert(bo, HisRegistration.class);
        validEntityBeforeSave(update);
        assert update != null;
        if (update.getStatus() == 1) update.setStatus(500);

        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(HisRegistration entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除挂号记录信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }


    //---------------------------小程序--------------------------

    /**
     * 查询挂号记录
     *
     * @param id 主键
     * @return 挂号记录
     */
    @Override
    public HisRegistrationVo xcxQueryById(Long id) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        HisRegistrationVo hisRegistrationVo = baseMapper.selectVoById(id);
        if (!StringUtils.equals(loginUser.getUserId().toString(), hisRegistrationVo.getMemberId().toString())) {
            new RuntimeException("非本人挂号记录，禁止查看");
        }

        hisRegistrationVo.setHisPatientVo(patientMapper.selectVoById(hisRegistrationVo.getPatientId()));
        hisRegistrationVo.setHisDoctorVo(doctorMapper.selectDoctorById(hisRegistrationVo.getDoctorId()));

        return hisRegistrationVo;
    }


    /**
     * 分页查询挂号记录列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 挂号记录分页列表
     */
    @Override
    public TableDataInfo<HisRegistrationVo> xcxQueryPageList(HisRegistrationBo bo, PageQuery pageQuery) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        bo.setMemberId(loginUser.getUserId());

        Page<HisRegistrationVo> page = baseMapper.registrationList(pageQuery.build(), bo);
        page.getRecords().forEach(obj -> {
            obj.setHisPatientVo(patientMapper.selectVoById(obj.getPatientId()));
            obj.setHisDoctorVo(doctorMapper.selectDoctorById(obj.getDoctorId()));
            HisDoctorVo doctor = obj.getHisDoctorVo();
            SysOss oss = sysOssMapper.selectById(doctor.getPhoto());
            doctor.setPhotoUrl(oss != null ? oss.getUrl() : null);
        });
        // 查询就诊卡信息
        return TableDataInfo.build(page);
    }


    @Override
    public R<?> pay(String orderNo, String payType) {
        //获取用户信息
        LoginUser loginUser = LoginHelper.getLoginUser();
        HisMember member = memberMapper.selectById(loginUser.getUserId());


        //获取挂号费
        LambdaQueryWrapper<HisRegistration> registration = new LambdaQueryWrapper<HisRegistration>();
        registration.eq(HisRegistration::getOrderNumber, orderNo);
        registration.eq(HisRegistration::getDelFlag, 0);
        HisRegistrationVo hisRegistrationVo = registrationMapper.selectVoOne(registration);


        HisPatient patient = patientMapper.selectById(hisRegistrationVo.getPatientId());


        OrderModel orderModel = new OrderModel();
        orderModel.setOrderNumber(hisRegistrationVo.getOrderNumber());
        orderModel.setRemark(patient.getName() + "挂号订单");
        Double money = hisRegistrationVo.getTotalPrice().doubleValue();
        orderModel.setTotalFee(money);

        orderModel.setOpenId(member.getOpenId());
        orderModel.setOrderId(hisRegistrationVo.getOrderNumber());
        R<?> result = paymentController.pay(String.valueOf(payType), orderModel);


        return result;
    }


    @Override
    public Boolean updateRegistration(R resultMag) {
        boolean flag = false;
        ReturnOrderModel returnOrderModel = (ReturnOrderModel) resultMag.getData();
        //根据订单id查询订单
        if (returnOrderModel.getResultCode() == 1) {
            LambdaQueryWrapper<HisRegistration> lq = new LambdaQueryWrapper<>();
            lq.eq(HisRegistration::getOrderNumber, returnOrderModel.getOrderNumber());
            lq.eq(HisRegistration::getDelFlag, 0);
            HisRegistration byOrderNumber = baseMapper.selectOne(lq);
            if (byOrderNumber != null) {
                //待诊断（已支付）
                byOrderNumber.setStatus(OrderStatusConstant.REGISTER_PAID);
                byOrderNumber.setPayPrice(byOrderNumber.getTotalPrice());
                byOrderNumber.setPayTime(DateUtils.getNowDate());
                baseMapper.updateById(byOrderNumber);
                //返回值
                flag = true;
            }
        }
        return flag;
    }

    @Override
    public Boolean cancel(HisRegistrationBo bo) {
        LoginUser loginUser = LoginHelper.getLoginUser();

        HisRegistration hisRegistration = baseMapper.selectById(bo.getId());
        if (!hisRegistration.getMemberId().equals(loginUser.getUserId())) {
            throw new ServiceException("操作失败，当前登录用户与就诊卡用户不匹配");
        }
        if (hisRegistration.getStatus().equals(OrderStatusConstant.REGISTER_PAID)) {
            throw new ServiceException("已支付订单，请申请退款");
        }
        if (hisRegistration.getStatus().equals(OrderStatusConstant.REGISTER_COMPLETE)) {
            throw new ServiceException("已完成订单！");
        }
        if (hisRegistration.getStatus().equals(OrderStatusConstant.REGISTER_REFUND)) {
            throw new ServiceException("已退款订单！");
        }
        hisRegistration.setStatus(OrderStatusConstant.REGISTER_CANCEL);

        return baseMapper.updateById(hisRegistration) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<?> update(HisRegistration registration) {

//        registration.setStatus(2l);
        //获取此条数据信息
        HisRegistration hisRegistration = baseMapper.selectById(registration.getId());
        //获取当前日期 格式化为 "yyyy-MM-dd"
        LocalDate currentDate = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String formattedDate = currentDate.format(formatter);


        // 获取 Date 对象
        Date registrationTime = hisRegistration.getRegistrationTime();

        // 定义日期格式
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

        // 将 Date 对象转换为字符串
        String datePart = dateFormat.format(registrationTime);


        if (formattedDate.equals(datePart)) {
            return R.error(500, "就诊当天无法退号");
        }
        // 已取消
        if (hisRegistration.getStatus().intValue() == OrderStatusConstant.REGISTER_CANCEL) {
            return R.error(500, "当前挂号订单已取消");
        }
        // 已退款
        if (hisRegistration.getStatus().intValue() == OrderStatusConstant.REGISTER_REFUND) {
            return R.error(500, "当前挂号订单已退款！");
        }

        // 已完成
        if (hisRegistration.getStatus().intValue() == OrderStatusConstant.REGISTER_COMPLETE) {
            return R.error(500, "当前挂号订单已完成，无法退款");
        }

        //待退款
        if (hisRegistration.getStatus().intValue() == OrderStatusConstant.REGISTER_REFUNDING) {
            return R.error(500, "当前挂号订单正在退款中，请勿重复发起退款");
        }

        //判断挂号日期是否小于当前日期
        if (datePart.compareTo(formattedDate) < 0) {
            return R.error(500, "挂号日期已过，无法退款");
        }

        if (hisRegistration.getTotalPrice().doubleValue() != 0.0) {
            // 退费
            HisMemberRefund hisMemberRefund = memberRefundService.getByRegistrantId(hisRegistration.getId().toString());
            if (Objects.isNull(hisMemberRefund)) {
                Long memberId = LoginHelper.getUserId();
                HisMember hisMember = memberMapper.selectById(memberId);
                hisMemberRefund = new HisMemberRefund();
                hisMemberRefund.setStatus("1")
                    .setOrderTreatId(hisRegistration.getId())
                    .setOrderType(OrderTypeConstant.ORDER_REGISTRATION_TREAT)
                    .setCreateTime(new Date())
                    .setCheckStatus("0")
                    .setRefundCause("患者取消订单")
                    .setOperator(hisMember.getName())
                    .setDoctorId(hisRegistration.getDoctorId())
                    .setMemberId(hisRegistration.getMemberId())
                    .setMoney(hisRegistration.getPayPrice().doubleValue());
                hisRegistration.setStatus(OrderStatusConstant.REGISTER_REFUNDING);
                memberRefundService.save(hisMemberRefund);
            } else {
                hisMemberRefund.setRefundCause("患者取消订单")
                    .setCheckStatus("0")
                    .setUpdateTime(new Date());
                memberRefundService.updateById(hisMemberRefund);
            }
            if (!"2".equals(hisMemberRefund.getStatus()) && "1".equals(hisMemberRefund.getCheckStatus())) {
                WxRefundResponseDTO dto = wxHandleUtil.refundResponseDTO(hisMemberRefund.getId());
                if (dto.isSuccess()) {
                    hisRegistration.setStatus(OrderStatusConstant.REGISTER_CANCEL);
                    hisMemberRefund.setStatus("2");
                    memberRefundService.updateById(hisMemberRefund);
                } else {
                    return R.error(500, "取消订单失败： " + dto.getMessage());
                }
            }
        } else {
            // 直接取消(未支付、带接诊且免费)
            hisRegistration.setStatus(OrderStatusConstant.REGISTER_CANCEL);
        }
        if (baseMapper.updateById(hisRegistration) > 0) {
            return R.ok();
        } else {
            return R.errorCode(CommonCode.UPDATE_FAIL);
        }

    }
}
